"""
组件API模块

提供组件管理相关的所有API接口，包括：
- 组件的增删改查
- 组件上传和管理
- 用户组件关联
- 组件装载和展示
"""
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
from datetime import datetime, timezone
from typing import Optional, List
import json
import os
import zipfile
import shutil
from pathlib import Path
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from db.models import Widget, UserWidget, User
from db.session import get_db
from apis.user_api import get_current_user
from services.permission import require_permission, PermissionCodes
from widgets import apis as loaded_apis, models as loaded_models

router = APIRouter(prefix="/widgets", tags=["组件管理"])

security = HTTPBearer()

class WidgetCreate(BaseModel):
    """组件创建请求模型"""
    name: str
    version: str
    description: Optional[str] = None
    category: Optional[str] = None
    config_schema: Optional[str] = None
    api_endpoints: Optional[str] = None
    frontend_files: Optional[str] = None

class WidgetUpdate(BaseModel):
    """组件更新请求模型"""
    name: Optional[str] = None
    version: Optional[str] = None
    description: Optional[str] = None
    category: Optional[str] = None
    is_active: Optional[bool] = None
    config_schema: Optional[str] = None
    api_endpoints: Optional[str] = None
    frontend_files: Optional[str] = None

class WidgetResponse(BaseModel):
    """组件响应模型"""
    id: int
    name: str
    version: str
    description: Optional[str]
    author_id: int
    category: Optional[str]
    is_active: bool
    config_schema: Optional[str]
    api_endpoints: Optional[str]
    frontend_files: Optional[str]
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True

class WidgetListResponse(BaseModel):
    widgets: List[WidgetResponse]
    total: int
    page: int
    pageSize: int

class UserWidgetCreate(BaseModel):
    widget_id: int
    config_data: Optional[str] = None

class UserWidgetResponse(BaseModel):
    id: int
    user_id: int
    widget_id: int
    is_enabled: bool
    config_data: Optional[str]
    widget: WidgetResponse

    class Config:
        from_attributes = True

@router.post("/", response_model=WidgetResponse, summary="创建组件")
@require_permission(PermissionCodes.WIDGET_CREATE)
async def create_widget(
    widget: WidgetCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    创建新组件
    
    Args:
        widget: 组件创建数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        WidgetResponse: 创建的组件信息
        
    Raises:
        HTTPException: 组件名称和版本已存在或权限不足时抛出异常
    """
    # 检查组件名称和版本是否已存在
    result = await db.execute(
        select(Widget).where(
            Widget.name == widget.name,
            Widget.version == widget.version
        )
    )
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="该组件名称和版本已存在"
        )
    
    # 创建组件
    db_widget = Widget(
        name=widget.name,
        version=widget.version,
        description=widget.description,
        author_id=current_user.id,
        category=widget.category,
        config_schema=widget.config_schema,
        api_endpoints=widget.api_endpoints,
        frontend_files=widget.frontend_files
    )
    
    db.add(db_widget)
    await db.commit()
    await db.refresh(db_widget)
    
    return db_widget

@router.post("/upload", summary="上传组件包")
@require_permission(PermissionCodes.WIDGET_CREATE)
async def upload_widget(
    file: UploadFile = File(...),
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    上传组件文件包
    
    Args:
        file: 组件包文件（ZIP格式）
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        WidgetResponse: 上传的组件信息
        
    Raises:
        HTTPException: 文件格式错误、缺少manifest或权限不足时抛出异常
    """
    """上传组件文件包"""
    if not file.filename.endswith('.zip'):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="只支持ZIP格式的组件包"
        )
    
    # 创建临时目录
    temp_dir = f"/tmp/widget_upload_{datetime.now().timestamp()}"
    os.makedirs(temp_dir, exist_ok=True)
    
    try:
        # 保存上传的文件
        zip_path = os.path.join(temp_dir, file.filename)
        with open(zip_path, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)
        
        # 解压文件
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            zip_ref.extractall(temp_dir)
        
        # 查找manifest.json文件
        manifest_path = os.path.join(temp_dir, "manifest.json")
        if not os.path.exists(manifest_path):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="组件包中缺少manifest.json文件"
            )
        
        # 读取manifest.json
        with open(manifest_path, 'r', encoding='utf-8') as f:
            manifest = json.load(f)
        
        # 验证manifest格式
        required_fields = ['name', 'version']
        for field in required_fields:
            if field not in manifest:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=f"manifest.json中缺少必需字段: {field}"
                )
        
        # 检查组件是否已存在
        result = await db.execute(
            select(Widget).where(
                Widget.name == manifest['name'],
                Widget.version == manifest['version']
            )
        )
        if result.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="该组件名称和版本已存在"
            )
        
        # 创建组件记录
        db_widget = Widget(
            name=manifest['name'],
            version=manifest['version'],
            description=manifest.get('description', ''),
            author_id=current_user.id,
            category=manifest.get('category', 'uncategorized'),
            config_schema=json.dumps(manifest.get('config_schema', {})),
            api_endpoints=json.dumps(manifest.get('api_endpoints', [])),
            frontend_files=json.dumps(manifest.get('frontend_files', {}))
        )
        
        db.add(db_widget)
        await db.commit()
        await db.refresh(db_widget)
        
        return db_widget
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"上传组件失败: {str(e)}"
        )
    finally:
        # 清理临时目录
        if os.path.exists(temp_dir):
            shutil.rmtree(temp_dir)

@router.get("/", response_model=WidgetListResponse, summary="获取组件列表")
@require_permission(PermissionCodes.WIDGET_READ)
async def get_all_widgets(
    page: int = 1,
    pageSize: int = 10,
    search: str = "",
    category: str = "",
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取组件列表（分页）
    
    Args:
        page: 页码
        pageSize: 每页数量
        search: 搜索关键词
        category: 分类筛选
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        WidgetListResponse: 组件列表和分页信息
        
    Raises:
        HTTPException: 权限不足时抛出异常
    """
    # 构建查询
    query = select(Widget)
    
    # 添加搜索条件
    if search:
        query = query.where(
            Widget.name.contains(search) | 
            Widget.description.contains(search)
        )
    
    # 添加分类筛选
    if category:
        query = query.where(Widget.category == category)
    
    # 获取总数
    count_query = select(func.count(Widget.id))
    if search:
        count_query = count_query.where(
            Widget.name.contains(search) | 
            Widget.description.contains(search)
        )
    if category:
        count_query = count_query.where(Widget.category == category)
    
    total_result = await db.execute(count_query)
    total = total_result.scalar() or 0
    
    # 添加分页
    query = query.offset((page - 1) * pageSize).limit(pageSize)
    
    # 执行查询
    result = await db.execute(query)
    widgets = result.scalars().all()
    
    return WidgetListResponse(
        widgets=[WidgetResponse(
            id=widget.id,
            name=widget.name,
            version=widget.version,
            description=widget.description,
            author_id=widget.author_id,
            category=widget.category,
            is_active=widget.is_active,
            config_schema=widget.config_schema,
            api_endpoints=widget.api_endpoints,
            frontend_files=widget.frontend_files,
            created_at=widget.create_time,
            updated_at=widget.update_time
        ) for widget in widgets],
        total=total,
        page=page,
        pageSize=pageSize
    )

@router.get("/{widget_id}", response_model=WidgetResponse, summary="获取组件详情")
@require_permission(PermissionCodes.WIDGET_READ)
async def get_widget(
    widget_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取组件详情
    
    Args:
        widget_id: 组件ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        WidgetResponse: 组件详细信息
        
    Raises:
        HTTPException: 组件不存在或权限不足时抛出异常
    """
    result = await db.execute(select(Widget).where(Widget.id == widget_id))
    widget = result.scalar_one_or_none()
    
    if not widget:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="组件不存在"
        )
    
    return widget

@router.put("/{widget_id}", response_model=WidgetResponse, summary="更新组件")
@require_permission(PermissionCodes.WIDGET_UPDATE)
async def update_widget(
    widget_id: int,
    widget_update: WidgetUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    更新组件信息
    
    Args:
        widget_id: 组件ID
        widget_update: 组件更新数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        WidgetResponse: 更新后的组件信息
        
    Raises:
        HTTPException: 组件不存在或权限不足时抛出异常
    """
    # 查找组件
    result = await db.execute(select(Widget).where(Widget.id == widget_id))
    widget = result.scalar_one_or_none()
    
    if not widget:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="组件不存在"
        )
    
    # 更新组件信息
    if widget_update.name is not None:
        widget.name = widget_update.name
    
    if widget_update.version is not None:
        widget.version = widget_update.version
    
    if widget_update.description is not None:
        widget.description = widget_update.description
    
    if widget_update.category is not None:
        widget.category = widget_update.category
    
    if widget_update.is_active is not None:
        widget.is_active = widget_update.is_active
    
    if widget_update.config_schema is not None:
        widget.config_schema = widget_update.config_schema
    
    if widget_update.api_endpoints is not None:
        widget.api_endpoints = widget_update.api_endpoints
    
    if widget_update.frontend_files is not None:
        widget.frontend_files = widget_update.frontend_files
    
    # 更新时间
    widget.update_time = datetime.now(timezone.utc)
    
    await db.commit()
    await db.refresh(widget)
    
    return widget

@router.delete("/{widget_id}", summary="删除组件")
@require_permission(PermissionCodes.WIDGET_DELETE)
async def delete_widget(
    widget_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    删除组件
    
    Args:
        widget_id: 组件ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        dict: 删除结果
        
    Raises:
        HTTPException: 组件不存在、有用户使用或权限不足时抛出异常
    """
    # 查找组件
    result = await db.execute(select(Widget).where(Widget.id == widget_id))
    widget = result.scalar_one_or_none()
    
    if not widget:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="组件不存在"
        )
    
    # 检查是否有用户使用此组件
    user_widget_result = await db.execute(select(UserWidget).where(UserWidget.widget_id == widget_id))
    if user_widget_result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="该组件下有用户，无法删除"
        )
    
    await db.delete(widget)
    await db.commit()
    
    return {"message": "组件删除成功"}

@router.get("/categories/list", summary="获取组件分类列表")
@require_permission(PermissionCodes.WIDGET_READ)
async def get_category_list(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取所有组件分类列表
    
    Args:
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        dict: 分类列表
        
    Raises:
        HTTPException: 权限不足时抛出异常
    """
    # 获取所有分类列表
    result = await db.execute(select(Widget.category).distinct().where(Widget.category.isnot(None)))
    categories = result.scalars().all()
    
    return {"categories": list(set(categories))}

@router.get("/my/widgets", response_model=List[UserWidgetResponse], summary="获取我的组件")
@require_permission(PermissionCodes.WIDGET_READ)
async def get_my_widgets(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    获取当前用户的所有组件
    
    Args:
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        List[UserWidgetResponse]: 用户组件列表
        
    Raises:
        HTTPException: 权限不足时抛出异常
    """
    # 获取用户的组件
    result = await db.execute(
        select(UserWidget, Widget)
        .join(Widget, UserWidget.widget_id == Widget.id)
        .where(UserWidget.user_id == current_user.id)
    )
    
    user_widgets = []
    for uw, widget in result:
        user_widgets.append(UserWidgetResponse(
            id=uw.id,
            user_id=uw.user_id,
            widget_id=uw.widget_id,
            is_enabled=uw.is_enabled,
            config_data=uw.config_data,
            widget=WidgetResponse(
                id=widget.id,
                name=widget.name,
                version=widget.version,
                description=widget.description,
                author_id=widget.author_id,
                category=widget.category,
                is_active=widget.is_active,
                config_schema=widget.config_schema,
                api_endpoints=widget.api_endpoints,
                frontend_files=widget.frontend_files,
                created_at=widget.create_time,
                updated_at=widget.update_time
            )
        ))
    
    return user_widgets

@router.post("/my/widgets", response_model=UserWidgetResponse, summary="添加用户组件")
@require_permission(PermissionCodes.WIDGET_READ)
async def add_user_widget(
    user_widget: UserWidgetCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    为用户添加组件
    
    Args:
        user_widget: 用户组件创建数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        UserWidgetResponse: 创建的用户组件信息
        
    Raises:
        HTTPException: 组件不存在或已添加时抛出异常
    """
    # 检查组件是否存在
    result = await db.execute(select(Widget).where(Widget.id == user_widget.widget_id))
    widget = result.scalar_one_or_none()
    
    if not widget:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="组件不存在"
        )
    
    # 检查是否已添加
    existing_result = await db.execute(
        select(UserWidget).where(
            UserWidget.user_id == current_user.id,
            UserWidget.widget_id == user_widget.widget_id
        )
    )
    if existing_result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="已添加该组件"
        )
    
    # 添加用户组件
    db_user_widget = UserWidget(
        user_id=current_user.id,
        widget_id=user_widget.widget_id,
        config_data=user_widget.config_data
    )
    
    db.add(db_user_widget)
    await db.commit()
    await db.refresh(db_user_widget)
    
    return UserWidgetResponse(
        id=db_user_widget.id,
        user_id=db_user_widget.user_id,
        widget_id=db_user_widget.widget_id,
        is_enabled=db_user_widget.is_enabled,
        config_data=db_user_widget.config_data,
        widget=WidgetResponse(
            id=widget.id,
            name=widget.name,
            version=widget.version,
            description=widget.description,
            author_id=widget.author_id,
            category=widget.category,
            is_active=widget.is_active,
            config_schema=widget.config_schema,
            api_endpoints=widget.api_endpoints,
            frontend_files=widget.frontend_files,
            created_at=widget.create_time,
            updated_at=widget.update_time
        )
    )

@router.put("/my/widgets/{user_widget_id}", response_model=UserWidgetResponse, summary="更新用户组件配置")
@require_permission(PermissionCodes.WIDGET_READ)
async def update_user_widget(
    user_widget_id: int,
    config_data: str,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    更新用户组件配置
    
    Args:
        user_widget_id: 用户组件ID
        config_data: 配置数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        UserWidgetResponse: 更新后的用户组件信息
        
    Raises:
        HTTPException: 用户组件不存在时抛出异常
    """
    # 查找用户组件
    result = await db.execute(
        select(UserWidget).where(
            UserWidget.id == user_widget_id,
            UserWidget.user_id == current_user.id
        )
    )
    user_widget = result.scalar_one_or_none()
    
    if not user_widget:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户组件不存在"
        )
    
    # 更新配置数据
    user_widget.config_data = config_data
    user_widget.update_time = datetime.now(timezone.utc)
    
    await db.commit()
    await db.refresh(user_widget)
    
    # 获取组件信息
    widget_result = await db.execute(select(Widget).where(Widget.id == user_widget.widget_id))
    widget = widget_result.scalar_one_or_none()
    
    return UserWidgetResponse(
        id=user_widget.id,
        user_id=user_widget.user_id,
        widget_id=user_widget.widget_id,
        is_enabled=user_widget.is_enabled,
        config_data=user_widget.config_data,
        widget=WidgetResponse(
            id=widget.id,
            name=widget.name,
            version=widget.version,
            description=widget.description,
            author_id=widget.author_id,
            category=widget.category,
            is_active=widget.is_active,
            config_schema=widget.config_schema,
            api_endpoints=widget.api_endpoints,
            frontend_files=widget.frontend_files,
            created_at=widget.create_time,
            updated_at=widget.update_time
        )
    )

@router.delete("/my/widgets/{user_widget_id}", summary="删除用户组件")
@require_permission(PermissionCodes.WIDGET_READ)
async def delete_user_widget(
    user_widget_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    删除用户组件
    
    Args:
        user_widget_id: 用户组件ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        dict: 删除结果
        
    Raises:
        HTTPException: 用户组件不存在时抛出异常
    """
    # 查找用户组件
    result = await db.execute(
        select(UserWidget).where(
            UserWidget.id == user_widget_id,
            UserWidget.user_id == current_user.id
        )
    )
    user_widget = result.scalar_one_or_none()
    
    if not user_widget:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户组件不存在"
        )
    
    await db.delete(user_widget)
    await db.commit()
    
    return {"message": "用户组件删除成功"}

@router.get("/loaded", summary="获取已加载的组件")
@require_permission(PermissionCodes.WIDGET_READ)
async def get_loaded_widgets(
    current_user: User = Depends(get_current_user)
):
    """
    获取已加载的组件列表
    
    Args:
        current_user: 当前用户对象
        
    Returns:
        dict: 已加载组件信息
        
    Raises:
        HTTPException: 权限不足时抛出异常
    """
    """获取已加载的组件列表"""
    loaded_widget_info = []
    
    # 获取已加载的API信息
    for api in loaded_apis:
        loaded_widget_info.append({
            "type": "api",
            "prefix": api.prefix,
            "tags": api.tags
        })
    
    # 获取已加载的模型信息
    for model in loaded_models:
        loaded_widget_info.append({
            "type": "model",
            "name": model.__name__,
            "table": model.__tablename__ if hasattr(model, '__tablename__') else None
        })
    
    return {
        "loaded_widgets": loaded_widget_info,
        "api_count": len(loaded_apis),
        "model_count": len(loaded_models)
    }